-module(event_generator_nth).
-include_lib("event_model.hrl").

-export([init/5]).

init(From, MeanLength, Numbers,Rates,Sources) ->
  io:format("Begin Generated Events...~n"),
  Events = event_sort(get_init_events_with_rates(Numbers,Rates,Sources)),
  edm_utils:reset_random(),
  NewEvents = init_plength(MeanLength,Events),
  io:format("Finish Generated Events~n"),
  From ! ok,
  run(NewEvents).

get_init_events_with_rates(Ns, Rates,Sources)->
  get_init_events_with_rates(Ns,Rates,[],Sources).

get_init_events_with_rates(_,[],Events,_)->
  Events;

get_init_events_with_rates([HN|TN], [H|T], Events,[HS|TS]) ->
  edm_utils:reset_random(),
  NewEvents = get_init_events(HN, H, HS),
  get_init_events_with_rates(TN,T,lists:append(Events, NewEvents), TS).

event_sort(Events)->
  lists:sort(fun(E1, E2)->event_sort_method(E1,E2) end, Events).

event_sort_method(Event1, Event2) ->
  #event{packet=#packet{timestamps=TS1}} = Event1,
  [HTS1|_]=TS1,
  #timestamp{atime=Atime1} = HTS1,
  #event{packet=#packet{timestamps=TS2}} = Event2,
  [HTS2|_]=TS2,
  #timestamp{atime=Atime2} = HTS2,
  (Atime2>=Atime1).

get_init_events(N, Rate,Sources)->
  get_init_events(N, Rate, [], 0, Sources).

get_init_events(N, Rate, Events, Time, Sources)->
  if
    N>0 ->
      NewTime = edm_utils:exp_random(1/Rate)+Time,
      NE = 1,
      %io:format("N(~p):~p~n",[N,NewTime]),
      % Be careful, only when NE==1
      [ES|_] = get_arrive_events(NE, [], NewTime, Sources),
      get_init_events(N-NE, Rate, [ES|Events], NewTime,Sources);
    true ->
      Events
  end.

run(Events) ->
  run(Events, 1).

run(Events,N)->
  %io:format("Event Generator left:~p~n",[length(Events)-N+1]),
  if
    length(Events) >= N ->
      receive
        {From, {one}} ->
          H=lists:nth(N,Events),
          From ! {self(), {have, [H]}},
          run(Events, N+1);
        {From, {range, {WaitTime, Compeletime}}} ->
          {NowEvents, NewN} = get_events(WaitTime, Compeletime, Events, N),
          From ! {self(), {have, NowEvents}},
          %io:format("NowEvents size:~p~n",[length(NowEvents)]),
          run(Events, NewN)
      end;
    true ->
      receive
        {From, _} ->
          From ! {self(), {empty}}
      end,
      run(Events, N)
  end
  .

get_events(BeginTime, EndTime, Events,N) ->
  get_events(BeginTime, EndTime, [], Events,N).

get_events(BeginTime, EndTime, NowEvents, Events, N)->
  if
    length(Events) >=N ->
      H = lists:nth(N, Events),
      #event{packet=Packet} = H,
      #packet{timestamps=Timestamps} = Packet,
      [HTS|_] = Timestamps,
      #timestamp{atime=Atime} = HTS,
      if
        EndTime=<Atime ->
          {NowEvents, N};
        true ->
          %io:format("B:~p,E:~p,A:~p~n",[BeginTime,EndTime,Atime]),
          get_events(BeginTime, EndTime, lists:append(NowEvents, [H]), Events, N+1)
      end;
    true ->
      {NowEvents, N}
  end.

get_arrive_events(0, E, _,_)->
  E;

get_arrive_events(N, E, Time, Sources)->
  [H|_]=Sources,
  Event = #event{packet=#packet{sources=Sources, now_source_id=H, timestamps=[#timestamp{atime=Time}]}},
  get_arrive_events(N-1, [Event|E], Time, Sources).

init_plength(Mean, Events)->
  init_plength(Mean, [], Events).

init_plength(_, NewEvents, [])->
  lists:reverse(NewEvents);

init_plength(Mean, NewEvents, [H|T])->
  #event{packet=Packet}= H,
  NewPacket = Packet#packet{plength=edm_utils:exp_random(Mean)},
  Event = H#event{packet=NewPacket},
  init_plength(Mean, [Event|NewEvents], T).

